package com.dawn.system.sys.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.dawn.commons.utils.ContextHolderUtils;
import com.dawn.commons.utils.Md5Utils;
import com.dawn.commons.utils.mail.MailUtil;
import com.dawn.commons.utils.mail.MailVo;
import com.dawn.commons.web.model.AjaxResponse;
import com.dawn.commons.web.model.DataGrid;
import com.dawn.system.sys.dao.UserMapper;
import com.dawn.system.sys.entity.User;
import com.dawn.system.sys.service.UserService;

@Service
public class UserServiceImpl implements UserService {

	@Autowired
	private UserMapper mapper;

	@CacheEvict(value = "SystemCache", allEntries = true)
	@Override
	public void add(User record) {
		String password = (null == record.getPassword() ? "" : record.getPassword());
		record.randomSalt();
		record.setPassword(encryptPassword(record.getAccount(), password, record.getSalt()));

		this.mapper.insertSelective(record);
	}

	@CacheEvict(value = "SystemCache", allEntries = true)
	@Override
	public void delete(long id) {
		this.mapper.deleteByPrimaryKey(id);
	}

	@CacheEvict(value = "SystemCache", allEntries = true)
	@Override
	public void deleteBatch(Long[] ids) {
		this.mapper.deleteByPrimaryKeys(ids);
	}

	@CacheEvict(value = "SystemCache", allEntries = true)
	@Override
	public void update(User record) {
		this.mapper.updateByPrimaryKeySelective(record);
	}

	@Cacheable(value = "SystemCache", key = "#root.targetClass +\".\"+ #root.methodName + (\"(\"+#id+\")\")")
	@Override
	public User get(long id) {
		return this.mapper.selectByPrimaryKey(id);
	}

	@Cacheable(value = "SystemCache", key = "#root.targetClass +\".\"+ #root.methodName + (\"()\")")
	@Override
	public List<User> getAllList(User record) {
		return this.mapper.selectAllList(record);
	}

	@Cacheable(value = "SystemCache", key = "#root.targetClass +\".\"+ #root.methodName + (\"()\")")
	@Override
	public DataGrid<User> datagrid(User conditions) {
		DataGrid<User> dg = new DataGrid<User>();

		Map<String, Object> conditionsMap = new HashMap<String, Object>();
		conditionsMap.put("record", conditions);
		conditionsMap.put("offset", dg.getOffset());
		conditionsMap.put("rows", dg.getPageSize());

		List<User> list = this.mapper.selectAllListPage(conditionsMap);
		int count = this.mapper.getCount(conditionsMap);
		dg.setRows(list);
		dg.setTotal(count);

		return dg;
	}

	public boolean matches(User user, String newPassword) {
		return user.getPassword().equals(encryptPassword(user.getUsername(), newPassword, user.getSalt()));
	}

	private String encryptPassword(String account, String password, String salt) {
		Md5Utils.hash(account + password + salt);
		return Md5Utils.hash(account + password + salt);
	}

	@Override
	public AjaxResponse loginValidate(String account, String password) {
		AjaxResponse ajaxResponse = new AjaxResponse() ;
		if(null == account) {
			ajaxResponse.setStatus(false);
			ajaxResponse.setMessage("账号不能为空");
			return ajaxResponse ;
		}
		
		User record = new User() ;
		record.setAccount(account);
		record = this.mapper.selectOne(record) ;
		if(null != record) {
			if(null != record.getStatus() && record.getStatus() == -1) {
				ajaxResponse.setStatus(false);
				ajaxResponse.setMessage("账号已注销");
				return ajaxResponse;
			} else if(null != record.getStatus() && record.getStatus() == 2) {
				ajaxResponse.setStatus(false);
				ajaxResponse.setMessage("账号已被锁定");
				return ajaxResponse;
			}
			
			if(matches(record, password)) {
				ajaxResponse.setMessage("验证成功");
				ajaxResponse.setObj(record);
				return ajaxResponse;
			} else {
				ajaxResponse.setStatus(false);
				ajaxResponse.setMessage("验证失败");
				return ajaxResponse;
			}
			
		} else {
			ajaxResponse.setStatus(false);
			ajaxResponse.setMessage("该账号不存在");
			return ajaxResponse;
		}
	}

	@Override
	public AjaxResponse iForgotPwd(User dto) {
		AjaxResponse ajaxResponse = new AjaxResponse();

		User user = this.mapper.selectOne(dto);
		if (null != user) {
			generatorRestPassLink(user);
			ajaxResponse.setMessage("邮件已发到你在该系统注册的邮件中，请按邮件提示重设密码。");
		} else {
			ajaxResponse.setStatus(false);
			ajaxResponse.setMessage("账号不存在！");
		}

		return ajaxResponse;
	}

	private boolean generatorRestPassLink(User user) {
		String secretKey = UUID.randomUUID().toString(); // 密钥
		Date outDate = new Date(System.currentTimeMillis() + 30 * 60 * 1000);// 30分钟后过期
		long date = outDate.getTime()/ 1000 * 1000 ;
		String key = user.getUsername() + "$" + date + "$" + secretKey;
		String digitalSignature = Md5Utils.hash(key);// 数字签名

		User record = new User();
		record.setId(user.getId());
		record.setValidateCode(secretKey);
		record.setOutDatetime(new Date(date));
		this.mapper.updateByPrimaryKeySelective(record);
		
		HttpServletRequest request = ContextHolderUtils.getRequest();
		String path = request.getContextPath();
		String basePath = request.getScheme() + "://" + request.getServerName()
				+ ":" + request.getServerPort() + path + "/";
		
		String resetPassHref = basePath + "admin/sys/user/checkLink?sid=" + digitalSignature
				+ "&account=" + user.getUsername();
		String emailContent = "请勿回复本邮件.点击下面的链接,重设密码<br/><a href="
                + resetPassHref + " target='_BLANK'>" + resetPassHref
                + "</a>  或者    <a href=" + resetPassHref
                + " target='_BLANK'>点击我重新设置密码</a>"
                + "<br/>tips:本邮件超过30分钟,链接将会失效，需要重新申请'找回密码'" + key
                + "\t" + digitalSignature;
		try {
			MailVo mv = new MailVo() ;
			mv.setSubject("Dawn-密码找回");
			mv.setRecipientTO(user.getEmail());
			mv.setContent(emailContent);
			
			MailUtil.send(mv) ;
			
		} catch (Exception e) {
			e.printStackTrace();
		}

		return true;
	}

	@Override
	public AjaxResponse checkResetLink(String sid, String account) {
		AjaxResponse ajaxResponse = new AjaxResponse();

		if (null != sid && sid.equals("") || null != account && account.equals("")) {
			ajaxResponse.setStatus(false);
			ajaxResponse.setMessage("链接不完整,请重新生成！");
			return ajaxResponse;
		}

		User dto = new User();
		dto.setAccount(account);
		User user = this.mapper.selectOne(dto);
		if (null != user) {
			long outDateTime = (user.getOutDatetime().getTime()/1000*1000) ;

			// 表示已经过期
			if (outDateTime <= System.currentTimeMillis()) {
				ajaxResponse.setStatus(false);
				ajaxResponse.setMessage("链接已经过期,请重新申请找回密码！");
				return ajaxResponse;
			}

			String key = user.getUsername() + "$" + outDateTime + "$" + user.getValidateCode();
			String digitalSignature = Md5Utils.hash(key);// 数字签名
			
			//链接验证通过 转到修改密码页面
			if(digitalSignature.equals(sid)) {
				ajaxResponse.setObj(user);
				return ajaxResponse;
			} else {
				ajaxResponse.setStatus(false);
				ajaxResponse.setMessage("链接不正确，是否已经过期了或已修改过?");
				return ajaxResponse;
			}

		} else {
			ajaxResponse.setStatus(false);
			ajaxResponse.setMessage("链接错误,无法找到匹配用户,请重新申请找回密码.");
			return ajaxResponse;
		}
	}

	@Override
	public AjaxResponse changePwd(User dto) {
		AjaxResponse ajaxResponse = new AjaxResponse() ;
		
		if(null != dto && null != dto.getPassword() && !"".equals(dto.getPassword().trim())) {
			User user = this.mapper.selectOne(dto) ;
			if(null != user) {
				User record = new User() ;
				record.setId(user.getId());
				record.randomSalt();
				record.setPassword(encryptPassword(dto.getAccount(), dto.getPassword(), record.getSalt()));
				record.setValidateCode("-");//标示该密码已修改过，如需再修改，需重设申请找回密码
				
				this.mapper.updateByPrimaryKeySelective(record) ;
				
				ajaxResponse.setMessage("重设密码成功，返回登录页面");
				return ajaxResponse;
			} else {
				ajaxResponse.setStatus(false);
				ajaxResponse.setMessage("密码已修改过，如需再修改，需重设申请找回密码.");
				return ajaxResponse;
			}
		} else {
			ajaxResponse.setStatus(false);
			ajaxResponse.setMessage("密码重设失败，原因：数据不完整");
			return ajaxResponse;
		}
	}
}
